#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <string.h>
#include "skein.h"
#include "threefish.h"

void print_bytes(uint8_t *bytes, uint16_t byteslen)
{
	int i;
	for (i=0; i<byteslen; i++) {
		printf("%02x", bytes[i]);
	}
}

void print_words(uint64_t *words, uint16_t wordslen)
{
	int i;
	for (i=0; i<wordslen; i++) {
		printf("0x%"PRIx64",", words[i]);
	}
}

void test_threefish_words_only() {
	int i;
	struct tf_ctx ctx;
	uint64_t plainwords[8];
	uint64_t result[8];
	uint64_t correct_result[8] = {
		0xcff449e3a52347deLLU,
		0x6ffdfc5033cc91c1LLU,
		0x394d3e933a2f38e7LLU,
		0x3dfda066b7a5a792LLU,
		0xe043752fc05cb4a5LLU,
		0x915788f0d99f4588LLU,
		0x119906342566efbfLLU,
		0xe9e0a02c5b1bb170LLU
	};

	for (i=0; i<8; i++) {
		ctx.key[i] = i*2;
		plainwords[i] = i;
	}
	memset(ctx.tweak, 0, 16);
	tf_prep(&ctx);
	tf_encrypt(&ctx, plainwords, result, 0);

	printf("Testing endian agnostic Threefish...\t");
	if(memcmp(result, correct_result, 64) == 0) {
		printf("SUCCESS\n");
	} else {
		printf("FAILURE\nresult: ");
		print_words(result, 8);
		printf ("\n");
	}
}

void test_skein_vectors()
{
	int i;
	struct skein_ctx ctx;
	uint8_t msg[128];
	uint8_t result[64];
	uint8_t correct_result1[64] = {
		0x71,0xb7,0xbc,0xe6,0xfe,0x64,0x52,0x22,
		0x7b,0x9c,0xed,0x60,0x14,0x24,0x9e,0x5b,
		0xf9,0xa9,0x75,0x4c,0x3a,0xd6,0x18,0xcc,
		0xc4,0xe0,0xaa,0xe1,0x6b,0x31,0x6c,0xc8,
		0xca,0x69,0x8d,0x86,0x43,0x07,0xed,0x3e,
		0x80,0xb6,0xef,0x15,0x70,0x81,0x2a,0xc5,
		0x27,0x2d,0xc4,0x09,0xb5,0xa0,0x12,0xdf,
		0x2a,0x57,0x91,0x02,0xf3,0x40,0x61,0x7a
	};
	uint8_t correct_result2[64] = {
		0x45,0x86,0x3b,0xa3,0xbe,0x0c,0x4d,0xfc,
		0x27,0xe7,0x5d,0x35,0x84,0x96,0xf4,0xac,
		0x9a,0x73,0x6a,0x50,0x5d,0x93,0x13,0xb4,
		0x2b,0x2f,0x5e,0xad,0xa7,0x9f,0xc1,0x7f,
		0x63,0x86,0x1e,0x94,0x7a,0xfb,0x1d,0x05,
		0x6a,0xa1,0x99,0x57,0x5a,0xd3,0xf8,0xc9,
		0xa3,0xcc,0x17,0x80,0xb5,0xe5,0xfa,0x4c,
		0xae,0x05,0x0e,0x98,0x98,0x76,0x62,0x5b
	};
	uint8_t correct_result3[64] = {
		0x91,0xCC,0xA5,0x10,0xC2,0x63,0xC4,0xDD,
		0xD0,0x10,0x53,0x0A,0x33,0x07,0x33,0x09,
		0x62,0x86,0x31,0xF3,0x08,0x74,0x7E,0x1B,
		0xCB,0xAA,0x90,0xE4,0x51,0xCA,0xB9,0x2E,
		0x51,0x88,0x08,0x7A,0xF4,0x18,0x87,0x73,
		0xA3,0x32,0x30,0x3E,0x66,0x67,0xA7,0xA2,
		0x10,0x85,0x6F,0x74,0x21,0x39,0x00,0x00,
		0x71,0xF4,0x8E,0x8B,0xA2,0xA5,0xAD,0xB7
	};

	for (i=0; i<128; i++) {
		msg[i] = 255-i;
	}

	skein_init(&ctx, 512, NULL, 0);
	skein_update(&ctx, msg, 1);
	skein_final(&ctx, result, 1);
	printf("Testing Skein one-byte test vector...\t");
	if(memcmp(result, correct_result1, 64) == 0) {
		printf("SUCCESS\n");
	} else {
		printf("FAILURE\nresult: ");
		print_bytes(result, 64);
		printf("\n");
	}
	
	skein_init(&ctx, 512, NULL, 0);
	skein_update(&ctx, msg, 64);
	skein_final(&ctx, result, 1);
	printf("Testing Skein 64-byte test vector...\t");
	if(memcmp(result, correct_result2, 64) == 0) {
		printf("SUCCESS\n");
	} else {
		printf("FAILURE\nresult: ");
		print_bytes(result, 64);
		printf("\n");
	}

	skein_init(&ctx, 512, NULL, 0);
	skein_update(&ctx, msg, 128);
	skein_final(&ctx, result, 1);
	printf("Testing Skein 128-byte test vector...\t");
	if(memcmp(result, correct_result3, 64) == 0) {
		printf("SUCCESS\n");
	} else {
		printf("FAILURE\nresult: ");
		print_bytes(result, 64);
		printf("\n");
	}
}

int main ()
{
	test_threefish_words_only();
	test_skein_vectors();

	return (0);
}

